/*
* BSTimelineModule
*
* Ken Frederick
* frederickk@google.com
*
*/


var BSTimelineBase = {
    // property constants
    // TODO: implement a Date() object
    days_EEEE: [
        'Sunday',
        'Monday',
        'Tuesday',
        'Wednesday',
        'Thursday',
        'Friday',
        'Saturday'
    ],
    months_MMMM: [
        'January',
        'February',
        'March',
        'April',
        'May',
        'June',
        'July',
        'August',
        'September',
        'October',
        'November',
        'December'
    ],


    /**
     *
     * http://stackoverflow.com/questions/4507784/snap-to-grid-functionality-using-javascript
     *
     * @param {Number} val
     *      value to snap
     * @param {Number} snapInc
     *      increment to snap value to
     * @param {Function} roundFunction
     *      (optiona) rounding function
     *
     * @return {Number} snapped value
     *
     * @example
     * var snapped = snap(0.66, 0.2); // 0.6
     *
     */
    snap: function(val, snapInc, roundFunction) {
        roundFunction = roundFunction || Math.round;
        return snapInc * roundFunction(val / snapInc);
    },


    /**
     * Combine two associative arrays together
     * @see {@link http://stackoverflow.com/questions/929776/merging-associative-arrays-javascript} (modified)
     *
     * @example
     * var arr1 = {foo: 'boom', bar: 'vroom', baz: 'croon'};
     * var arr2 = {quux: 'goon', quuux: 'boon'};
     * var arrNew = bs.utils.combine(arr1, arr2); // {foo: 'boom', bar: 'vroom', baz: 'croon', quux: 'goon', quuux: 'boon'}
     *
     * @memberOf BSLib.utils
     *
     * @param {Array} arr
     *
     * @return {Array} new combined associatibe Array
     *
     */
    combine: function(base, arr) {
        for (var item in base) {
            arr[item] = (arr[item] !== undefined)
                ? arr[item]
                : base[item];
        }
        return arr;
    },


    /**
     * Create a random HEX color
     *
     * @return {String} random HEX color string
     *
     */
    randomHex: function() {
        return '#' + Math.floor(Math.random() * 16777215).toString(16);
    }

};



/*
 * TODO: following code chunks pulled in from bslib.js,
 *       eventually remove unecessary bits
 */

// ------------------------------------------------------------------------
//
// Arrays
// Extensions to JavaScript Array may be bad form... but whatever
//
// ------------------------------------------------------------------------

/**
 *
 * @return {Number} median value
 *
 */
Array.prototype.median = function() {
    var type = Object.prototype.toString.call(this).split(/\W/)[2];
    if (type === 'Array') {
        var median = 0;
        this.sort();
        if (this.length % 2 === 0) {
            median = (this[this.length / 2 - 1] + this[this.length / 2]) / 2;
        }
        else {
            median = this[(this.length - 1) / 2];
        }
        return median;
    }
};

/**
 * http://stackoverflow.com/questions/10359907/array-sum-and-average
 *
 * @return {Number} average  value
 *
 */
Array.prototype.average = function(){
    var type = Object.prototype.toString.call(this).split(/\W/)[2];
    if (type === 'Array') {
        var sum = 0;
        for (var i = 0; i < this.length, isFinite(this[i]); i++) {
            sum += parseFloat(this[i]);
        }
        return sum/this.length-1;
    }
};


/**
 * combines two Arrays
 *
 * @param {Array} arr
 *          Array object
 *
 * @return {Array} new merged Array object
 *
 */
Array.prototype.merge = function(arr, bShuffle) {
    var type = Object.prototype.toString.call(this).split(/\W/)[2];
    if (type === 'Array') {
        var output = this.concat(arr);
        return output;
    }
};


/*
 * combine two associative arrays together
 * http://stackoverflow.com/questions/929776/merging-associative-arrays-javascript (modified)
 *
 * @param {Array} arr
 *          Array object
 *
 * @return {Array} new combined associatibe Array
 *
 */
Array.prototype.combine = function(arr) {
    for(item in this) {
        arr[item] = (arr[item] != undefined)
            ? arr[item]
            : this[item];
    }
    return arr;
};


/**
 * find index of particular value within an array
 *
 * @param {String} query
 *          the value to search for within array
 *
 * @return {Number} index of object within array
 *
 */
Array.prototype.findIndex = function(query) {
    for (var i=this.length-1; i>=0; i--) {
        if (this[i].toLowerCase() === query.toLowerCase()) {
            break;
        }
    }
    return i;
};


/**
 *
 * @param {Number} start
 *          start position in array
 * @param {Number} stop
 *          stop position in array
 *
 * @return {Number} index of maximum value within array
 *
 */
Array.prototype.max = function(start, stop) {
    start = (start != undefined)
        ? start
        : 0;
    stop = (stop != undefined)
        ? stop
        : this.length;
    var max = start;

    for (var i=(start+1); i<stop; i++) if (this[i] > this[max]) max = i;
    return max;
};

/**
 *
 * @param {Number} start
 *          start position in array
 * @param {Number} stop
 *          stop position in array
 *
 * @return {Number} index of minimum value within array
 *
 */
Array.prototype.min = function(start, stop) {
    start = (start != undefined)
        ? start
        : 0;
    stop = (stop != undefined)
        ? stop
        : this.length;
    var min = start;

    for (var i=(start+1); i<stop; i++) if (this[i] < this[min]) min = i;
    return min;
};

/**
 *
 * http://jsfromhell.com/array/shuffle
 * http://www.brain4.de/programmierecke/js/arrayShuffle.php
 *
 * @return {Array} original array but with the order "shuffled"
 *
 */
Array.prototype.shuffle = function() {
    for (var j, x, i=this.length; i; j=parseInt(Math.random() * i), x=this[--i], this[i]=this[j], this[j]=x);
};

/**
 * Eliminate all non-unique elements from an Array
 *
 * @return {Object} unique element
 *
 */
Array.prototype.unique = function() {
    var u = [];
    o:for (var i=0, n=this.length; i<n; i++) {
        for (var x=0, y=u.length; x<y; x++) {
            if (u[x] == this[i]) {
                continue o;
            }
        }
        u[u.length] = this[i];
    }
    return u;
};

/**
 * Eliminate all duplicates from an Array
 * http://stackoverflow.com/questions/9229645/remove-duplicates-from-javascript-array
 *
 * @return {Array} original array without duplicates
 *
 */
Array.prototype.removeDuplicates = function() {
    var type = Object.prototype.toString.call(this).split(/\W/)[2];
    if (type === 'Array') {
        return this.reduce(function(accum, cur) {
            if (accum.indexOf(cur) === -1) accum.push(cur);
            return accum;
        }, [] );
    }
};

/**
 *
 * @param {Number} decimalPlaces
 *      number of decimal places
 *
 * @return {Array} original array with rounded values
 *
 */
Array.prototype.round = function(decimalPlaces) {
    var multi = Math.pow(10,decimalPlaces);
    for (var i = 0; i < this.length; i++) this[i] = Math.round(this[i] * multi)/multi;
    return this;
};



// ------------------------------------------------------------------------
//
// Strings
//
// ------------------------------------------------------------------------

/**
 * converts given string to Title Case
 * http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
 *
 * @return {String} input String in Title Case
 *
 */
String.prototype.toTitleCase = function() {
    return this.replace(/\w\S*/g, function(txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    });
};

/**
 * trims white space from left (start) of String
 * http://stackoverflow.com/questions/3000649/trim-spaces-from-start-and-end-of-string
 *
 * @return {String} trimmed input String
 *
 */
String.prototype.trimStart = function() {
    return this.replace(/^\s\s*/, '');
};
if (!String.prototype.trimLeft) {
    String.prototype.trimLeft = String.prototype.trimStart;
}

/**
 * trims white space from right (end) of String
 * http://stackoverflow.com/questions/3000649/trim-spaces-from-start-and-end-of-string
 *
 * @return {String} trimmed input String
 *
 */
String.prototype.trimEnd = function() {
    return this.replace(/\s\s*$/, '');
};
if (!String.prototype.trimRight) {
    String.prototype.trimRight = String.prototype.trimEnd;
}

/**
 * trims all white space from String
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
 *
 * @return {String} trimmed input string
 *
 */
if (!String.prototype.trim) {
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/gm, '');
    };
}

/**
 * converts String to Boolean value
 *
 * @return {Boolean}
 *
 */
String.prototype.toBool = function() {
    switch(this.toLowerCase()) {
            case 'true': case 'yes': case '1': return true;
            case 'false': case 'no': case '0': case null: return false;
            default: return Boolean(this);
    }
};
